home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_jnos / j109lxa4.tgz / j109lxa4.tar / telnet.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  10KB  |  504 lines

  1. /* Internet Telnet client
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by PA0GRI */
  5. #include <stdio.h>
  6. #ifdef    __TURBOC__
  7. #include <io.h>
  8. #include <fcntl.h>
  9. #endif
  10. #include "global.h"
  11. #include "config.h"
  12. #include "mbuf.h"
  13. #include "socket.h"
  14. #include "telnet.h"
  15. #include "session.h"
  16. #include "proc.h"
  17. #include "tty.h"
  18. #include "commands.h"
  19. #include "netuser.h"
  20.  
  21. static int filemode __ARGS((FILE *fp,int mode));
  22. #define    CTLZ    26
  23.  
  24. int Refuse_echo = 0;
  25. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  26.  
  27. #ifdef    DEBUG
  28. char *T_options[] = {
  29.     "Transmit Binary",
  30.     "Echo",
  31.     "",
  32.     "Suppress Go Ahead",
  33.     "",
  34.     "Status",
  35.     "Timing Mark"
  36. };
  37. #endif
  38.  
  39. #ifdef    MAILBOX
  40. /* Execute user BBS command */
  41. int
  42. dobbs(argc,argv,p)
  43. int argc;
  44. char *argv[];
  45. void *p;
  46. {
  47.     struct session *sp;
  48.     struct sockaddr_in fsocket;
  49.  
  50.     /*Make sure this comes from console - WG7J*/
  51.     if(Curproc->input != Command->input)
  52.         return 0;
  53.  
  54.     /* Allocate a session descriptor */
  55.     if((sp = newsession("Local BBS",TELNET,0)) == NULLSESSION){
  56.         tputs(TooManySessions);
  57.         return 1;
  58.     }
  59.     fsocket.sin_family = AF_INET;
  60.     if(argc < 3)
  61.         fsocket.sin_port = IPPORT_TELNET;
  62.     else
  63.         fsocket.sin_port = atoip(argv[2]);
  64.  
  65.     fsocket.sin_addr.s_addr = 0x7f000001L; /* 127.0.0.1 the loopback interface */
  66.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  67.         tputs(Nosock);
  68.         keywait(NULLCHAR,1);
  69.         freesession(sp);
  70.         return 1;
  71.     }
  72.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  73. }
  74. #endif /*MAILBOX*/
  75.  
  76. #ifdef ALLSESSIONS
  77. /* Execute user telnet command */
  78. int
  79. dotelnet(argc,argv,p)
  80. int argc;
  81. char *argv[];
  82. void *p;
  83. {
  84.     struct session *sp;
  85.     struct sockaddr_in fsocket;
  86.     int split = 0;
  87.  
  88.     /*Make sure this comes from console - WG7J*/
  89.     if(Curproc->input != Command->input)
  90.         return 0;
  91.  
  92. #ifdef ALLSERV
  93.     if((strlen(argv[0]) > 1) && (argv[0][1] == 't')) /* tty-link command */
  94.         split = 1;
  95. #endif
  96.  
  97.     /* Allocate a session descriptor */
  98.     if((sp = newsession(argv[1],TELNET,split)) == NULLSESSION){
  99.         tputs(TooManySessions);
  100.         return 1;
  101.     }
  102.     fsocket.sin_family = AF_INET;
  103.     if(argc < 3)
  104.         if(split)
  105.             fsocket.sin_port = IPPORT_TTYLINK;
  106.         else
  107.             fsocket.sin_port = IPPORT_TELNET;
  108.     else {
  109.         fsocket.sin_port = atoip(argv[2]);
  110.     }
  111.  
  112.     tprintf("Resolving %s... ",sp->name);
  113.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  114.         tprintf(Badhost,sp->name);
  115.         keywait(NULLCHAR,1);
  116.         freesession(sp);
  117.         return 1;
  118.     }
  119.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  120.         tputs(Nosock);
  121.         keywait(NULLCHAR,1);
  122.         freesession(sp);
  123.         return 1;
  124.     }
  125.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  126. }
  127. #endif
  128.  
  129. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  130. int
  131. tel_connect(sp,fsocket,len)
  132. struct session *sp;
  133. char *fsocket;
  134. int len;
  135. {
  136.     unsigned int index;
  137.     struct telnet tn;
  138.  
  139.     index = sp - Sessions;
  140.     memset((char *)&tn,0,sizeof(tn));
  141.     tn.eolmode = Tn_cr_mode;
  142.     tn.session = sp;    /* Upward pointer */
  143.     sp->cb.telnet = &tn;    /* Downward pointer */
  144.     sockmode(sp->s,SOCK_ASCII);    /* Default to ascii mode */
  145.  
  146.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  147.     if(connect(sp->s,fsocket,len) == -1){
  148.           tprintf("%s session %u failed: %s errno %d\n",
  149.          Sestypes[sp->type], index, sockerr(sp->s),errno);
  150.  
  151.         keywait(NULLCHAR,1);
  152.         freesession(sp);
  153.         return 1;
  154.     }
  155.     tprintf("%s session ",Sestypes[sp->type]);
  156.     tprintf("%u connected to %s\n",index,sp->name);
  157.     tnrecv(&tn);
  158.     return 0;
  159. }
  160.  
  161. /* Telnet input routine, common to both telnet and ttylink */
  162. void
  163. tnrecv(tn)
  164. struct telnet *tn;
  165. {
  166.     int c,s,index;
  167.     struct session *sp;
  168.     char *cp;
  169.  
  170.     sp = tn->session;
  171.     s = sp->s;
  172.  
  173.     index = sp - Sessions;
  174.  
  175.     /* Fork off the transmit process */
  176.     sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL,0);
  177.  
  178.     /* Process input on the connection */
  179.     while((c = recvchar(s)) != -1){
  180.         if(c != IAC){
  181. #ifdef notdef
  182.             /* Allow international character sets to pass - WG7J */
  183.             /* Ordinary character */
  184.             if(!tn->remote[TN_TRANSMIT_BINARY])
  185.                 c &= 0x7f;
  186. #endif
  187.             tputc((char)c);
  188.             continue;
  189.         }
  190.         /* IAC received, get command sequence */
  191.         c = recvchar(s);
  192.         switch(c){
  193.         case WILL:
  194.             c = recvchar(s);
  195.             willopt(tn,c);
  196.             break;
  197.         case WONT:
  198.             c = recvchar(s);
  199.             wontopt(tn,c);
  200.             break;
  201.         case DO:
  202.             c = recvchar(s);
  203.             doopt(tn,c);
  204.             break;
  205.         case DONT:
  206.             c = recvchar(s);
  207.             dontopt(tn,c);
  208.             break;
  209.         case IAC:    /* Escaped IAC */
  210.             tputc(IAC);
  211.             break;
  212.         }
  213.     }
  214.     /* A close was received from the remote host.
  215.      * Notify the user, kill the output task and wait for a response
  216.      * from the user before freeing the session.
  217.      */
  218.     sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
  219.     cp = sockerr(s);
  220.     tprintf("%s session %u", Sestypes[sp->type],index);
  221.     tprintf(" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
  222.     killproc(sp->proc1);
  223.     sp->proc1 = NULLPROC;
  224.     close_s(sp->s);
  225.     sp->s = -1;
  226.     keywait(NULLCHAR,1);
  227.     freesession(sp);
  228. }
  229.  
  230. /* User telnet output task, started by user telnet command */
  231. void
  232. tel_output(unused,tn1,p)
  233. int unused;
  234. void *tn1;
  235. void *p;
  236. {
  237.     struct session *sp;
  238.     int c;
  239.     struct telnet *tn;
  240.  
  241.     tn = (struct telnet *)tn1;
  242.     sp = tn->session;
  243.  
  244.     /* Send whatever's typed on the terminal */
  245.     while((c = recvchar(sp->input)) != EOF){
  246.         usputc(sp->s,(char)c);
  247.         if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
  248.             putc(c,sp->record);
  249.  
  250.         /* By default, output is transparent in remote echo mode.
  251.          * If eolmode is set, turn a cr into cr-null.
  252.          * This can only happen when in remote echo (raw) mode, since
  253.          * the tty driver normally maps \r to \n in cooked mode.
  254.          */
  255.         if(c == '\r' && tn->eolmode)
  256.             usputc(sp->s,'\0');
  257.  
  258.         if(tn->remote[TN_ECHO])
  259.             usflush(sp->s);
  260.     }
  261.     /* Make sure our parent doesn't try to kill us after we exit */
  262.     sp->proc1 = NULLPROC;
  263. }
  264. int
  265. doecho(argc,argv,p)
  266. int argc;
  267. char *argv[];
  268. void *p;
  269. {
  270.     if(argc < 2){
  271.         if(Refuse_echo)
  272.             tprintf("Refuse\n");
  273.         else
  274.             tprintf("Accept\n");
  275.     } else {
  276.         if(argv[1][0] == 'r')
  277.             Refuse_echo = 1;
  278.         else if(argv[1][0] == 'a')
  279.             Refuse_echo = 0;
  280.         else
  281.             return -1;
  282.     }
  283.     return 0;
  284. }
  285. /* set for unix end of line for remote echo mode telnet */
  286. int
  287. doeol(argc,argv,p)
  288. int argc;
  289. char *argv[];
  290. void *p;
  291. {
  292.     if(argc < 2){
  293.         if(Tn_cr_mode)
  294.             tprintf("null\n");
  295.         else
  296.             tprintf("standard\n");
  297.     } else {
  298.         if(argv[1][0] == 'n')
  299.             Tn_cr_mode = 1;
  300.         else if(argv[1][0] == 's')
  301.             Tn_cr_mode = 0;
  302.         else {
  303.             tprintf("Usage: %s [standard|null]\n",argv[0]);
  304.             return -1;
  305.         }
  306.     }
  307.     return 0;
  308. }
  309.  
  310. /* The guts of the actual Telnet protocol: negotiating options */
  311. void
  312. willopt(tn,opt)
  313. struct telnet *tn;
  314. int opt;
  315. {
  316.     int ack;
  317.  
  318. #ifdef    DEBUG
  319.     printf("recv: will ");
  320.     if(uchar(opt) <= NOPTIONS)
  321.         printf("%s\n",T_options[opt]);
  322.     else
  323.         printf("%u\n",opt);
  324. #endif
  325.     
  326.     switch(uchar(opt)){
  327.     case TN_TRANSMIT_BINARY:
  328.     case TN_ECHO:
  329.     case TN_SUPPRESS_GA:
  330.         if(tn->remote[uchar(opt)] == 1)
  331.             return;        /* Already set, ignore to prevent loop */
  332.         if(uchar(opt) == TN_ECHO){
  333.             if(Refuse_echo){
  334.                 /* User doesn't want to accept */
  335.                 ack = DONT;
  336.                 break;
  337.             } else {
  338.                 /* Put tty into raw mode */
  339.                 tn->session->ttystate.edit = 0;
  340.                 tn->session->ttystate.echo = 0;
  341.                 sockmode(tn->session->s,SOCK_BINARY);
  342.                 sockmode(tn->session->input,SOCK_BINARY);
  343.                 sockmode(tn->session->output,SOCK_BINARY);
  344.                 if(tn->session->record != NULLFILE)
  345.                     filemode(tn->session->record,SOCK_BINARY);
  346.  
  347.             }
  348.         }
  349.         tn->remote[uchar(opt)] = 1;
  350.         ack = DO;            
  351.         break;
  352.     default:
  353.         ack = DONT;    /* We don't know what he's offering; refuse */
  354.     }
  355.     answer(tn,ack,opt);
  356. }
  357. void
  358. wontopt(tn,opt)
  359. struct telnet *tn;
  360. int opt;
  361. {
  362. #ifdef    DEBUG
  363.     printf("recv: wont ");
  364.     if(uchar(opt) <= NOPTIONS)
  365.         printf("%s\n",T_options[uchar(opt)]);
  366.     else
  367.         printf("%u\n",uchar(opt));
  368. #endif
  369.     if(uchar(opt) <= NOPTIONS){
  370.         if(tn->remote[uchar(opt)] == 0)
  371.             return;        /* Already clear, ignore to prevent loop */
  372.         tn->remote[uchar(opt)] = 0;
  373.         if(uchar(opt) == TN_ECHO){
  374.             /* Put tty into cooked mode */
  375.             tn->session->ttystate.edit = 1;
  376.             tn->session->ttystate.echo = 1;
  377.             sockmode(tn->session->s,SOCK_ASCII);
  378.             sockmode(tn->session->input,SOCK_ASCII);
  379.             sockmode(tn->session->output,SOCK_ASCII);
  380.             if(tn->session->record != NULLFILE)
  381.                 filemode(tn->session->record,SOCK_ASCII);
  382.         }
  383.     }
  384.     answer(tn,DONT,opt);    /* Must always accept */
  385. }
  386. void
  387. doopt(tn,opt)
  388. struct telnet *tn;
  389. int opt;
  390. {
  391.     int ack;
  392.  
  393. #ifdef    DEBUG
  394.     printf("recv: do ");
  395.     if(uchar(opt) <= NOPTIONS)
  396.         printf("%s\n",T_options[uchar(opt)]);
  397.     else
  398.         printf("%u\n",uchar(opt));
  399. #endif
  400.     switch(uchar(opt)){
  401.     case TN_SUPPRESS_GA:
  402.         if(tn->local[uchar(opt)] == 1)
  403.             return;        /* Already set, ignore to prevent loop */
  404.         tn->local[uchar(opt)] = 1;
  405.         ack = WILL;
  406.         break;
  407.     default:
  408.         ack = WONT;    /* Don't know what it is */
  409.     }
  410.     answer(tn,ack,opt);
  411. }
  412. void
  413. dontopt(tn,opt)
  414. struct telnet *tn;
  415. int opt;
  416. {
  417. #ifdef    DEBUG
  418.     printf("recv: dont ");
  419.     if(uchar(opt) <= NOPTIONS)
  420.         printf("%s\n",T_options[uchar(opt)]);
  421.     else
  422.         printf("%u\n",uchar(opt));
  423. #endif
  424.     if(uchar(opt) <= NOPTIONS){
  425.         if(tn->local[uchar(opt)] == 0){
  426.             /* Already clear, ignore to prevent loop */
  427.             return;
  428.         }
  429.         tn->local[uchar(opt)] = 0;
  430.     }
  431.     answer(tn,WONT,opt);
  432. }
  433. void
  434. answer(tn,r1,r2)
  435. struct telnet *tn;
  436. int r1,r2;
  437. {
  438.     char s[3];
  439.  
  440. #ifdef    DEBUG
  441.     switch(r1){
  442.     case WILL:
  443.         printf("sent: will ");
  444.         break;
  445.     case WONT:
  446.         printf("sent: wont ");
  447.         break;
  448.     case DO:
  449.         printf("sent: do ");
  450.         break;
  451.     case DONT:
  452.         printf("sent: dont ");
  453.         break;
  454.     }
  455.     if(r2 <= NOPTIONS)
  456.         printf("%s\n",T_options[r2]);
  457.     else
  458.         printf("%u\n",r2);
  459. #endif
  460.  
  461.     s[0] = IAC;
  462.     s[1] = r1;
  463.     s[2] = r2;
  464.     send(tn->session->s,s,3,0);
  465. }
  466. #ifdef    __TURBOC__
  467. /* Set end-of-line translation mode on file */
  468. static int
  469. filemode(fp,mode)
  470. FILE *fp;
  471. int mode;
  472. {
  473.     int omode;
  474.  
  475.     if(fp == NULLFILE)
  476.         return -1;
  477.  
  478.     if(fp->flags & _F_BIN)
  479.         omode = SOCK_BINARY;
  480.     else
  481.         omode = SOCK_ASCII;
  482.  
  483.     switch(mode){
  484.     case SOCK_BINARY:
  485.         fp->flags = _F_BIN;
  486.         setmode(fileno(fp),O_BINARY);
  487.         break;
  488.     case SOCK_ASCII:
  489.         fp->flags &= ~_F_BIN;
  490.         setmode(fileno(fp),O_TEXT);
  491.         break;
  492.     }
  493.     return omode;
  494. }
  495. #else
  496. static int
  497. filemode(fp,mode)
  498. FILE *fp;
  499. int mode;
  500. {
  501.     return 0;
  502. }
  503. #endif
  504.